package osBasicLibrary

import (
	"fmt"
	"io"
	"os"
)

/**
os操作系统库 - 文件读取
- 2、权限
const (
	O_RDONLY int = syscall.O_RDONLY // 只读
	O_WRONLY int = syscall.O_WRONLY // 只写
	O_RDWR   int = syscall.O_RDWR   // 可读可写
	O_APPEND int = syscall.O_APPEND // a+模式: 写操作时将数据附加到文件尾部
	O_CREATE int = syscall.O_CREAT  // 如果文件不存在则新创建
	O_EXCL   int = syscall.O_EXCL   // 和O_CREATE配合使用，文件必须不存在
	O_SYNC   int = syscall.O_SYNC   // 打开文件用于异步IO
	O_TRUNC  int = syscall.O_TRUNC  // 打开时截断常规可写文件(如果可能，打开文件时清空文件内容)
)

type FileInfo interface {
	Name() 		string		// 文件的名称
	Size() 		int64		// 文件的大小
	Mode() 		FileMode	// 文件的模式
	ModTime() 	time.Time	// 文件的修改时间
	IsDir() 	bool		// 是否为目录
	Sys() 		interface{}	// 底层数据来源(可以返回nil)
}
*/

func HHTestFileStat() {
	/** 一、获取文件信息：文件名称、文件大小、修改时间等
	1、func (f *File) Stat() (fi FileInfo, err error) {}
	*/
	var filename string = "test1.txt"
	// file, err := os.OpenFile(filename, O_RDWR|O_CREATE, 0755)
	file, err := os.Create(filename)
	if err != nil {
		fmt.Println("error:", err)
		panic(err)
	}
	defer file.Close()

	fileInfo, _ := file.Stat()
	fileName := fileInfo.Name()
	fileSize := fileInfo.Size()
	fileMode := fileInfo.Mode()
	fileMdTime := fileInfo.ModTime()
	fileIsDir := fileInfo.IsDir()
	fileSys := fileInfo.Sys()
	fmt.Println("file name:", fileName)      // test.txt
	fmt.Println("file size:", fileSize)      // 0
	fmt.Println("file mode:", fileMode)      // -rwxr-xr-x
	fmt.Println("file md time:", fileMdTime) // 2023-06-13 22:57:13.141537823 +0800 CST
	fmt.Println("file is dir:", fileIsDir)   // false
	fmt.Println("file sys:", fileSys)        // ...
}

func HHTestFileRead() {
	/** 二、从文件中一次性读取b字节大小的数据，当读到文件末尾时，返回一个EOF错误
	1、func (f *File) Read(b []byte) (n int, err error) {}
	*/
	var body []byte
	var filename string = "test2.txt"
	file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		fmt.Println("error:", err)
		panic(err)
	}
	defer file.Close()

	for {
		buf := make([]byte, 4)
		n, err := file.Read(buf)
		if err == io.EOF {
			break
		}
		body = append(body, buf[:n]...)
	}
	fmt.Printf("body: %s\n", body) // hello world!
}

func HHTestFileReadAt() {
	/** 三、从文件中指定的位置(off)一次性读取b字节数据
	1、func (f *File) ReadAt(b []byte, off int64) (n int, err error) {}
	*/
	var filename string = "test3.txt"
	file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		fmt.Println("error:", err)
		panic(err)
	}
	defer file.Close()

	buf := make([]byte, 5)
	n, _ := file.ReadAt(buf, 6) // 从第6位开始读，读5位
	fmt.Printf("body: %s\n", buf[:n])
}

func HHTestFileReadDir() {
	/** 四、读取目录并返回排序好的文件以及子目录名切片
	1、func ReadDir(name string) ([]DirEntry, err error) {}
	*/
	filedir := "fmt"
	file, err := os.Open(filedir)
	if err != nil {
		fmt.Println("error:", err)
	}
	defer file.Close()

	dirs, err := file.ReadDir(-1)
	if err != nil {
		fmt.Println("error:", err)
	}
	for _, val := range dirs {
		fmt.Println("val name and is dir:", val.Name(), val.IsDir())
	}
}

func HHTestFileSeek() {
	/** 五、Seek设置下一次读/写的位置
	@partam offset -> 相对偏移量
	@param whence -> 决定相对位置：0:相对文件开头 1:相对当前呢位置 2:相对文件结尾
	@return -> 新的偏移量(相对开头)和可能的错误
	1、func (f *File) Seek(offset int64, whence int) (ret int64, err error) {}
	*/
	var filename string = "test5.txt"
	file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		fmt.Println("error:", err)
		panic(err)
	}
	defer file.Close()

	file.Seek(3, 0)
	buf := make([]byte, 10)
	n, _ := file.Read(buf)
	fmt.Printf("body: %s\n", buf[:n])
}
